#include "AESAlgorithm.h"
#include <iostream>
#include <string>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <memory>
#include <cstring>

#define CVVISION_KEY "CvvSecretKey2023"         // 密钥
using namespace CVV::Infrastructure::Utils;

AESAlgorithm *AESAlgorithm::getInstance()
{
    static AESAlgorithm instance;
    return &instance;
}

std::string AESAlgorithm::cbcEncrypt(const std::string &plaintext, const std::string &key)
{
    std::string keyStr = key;
    if (keyStr.empty()) {
        keyStr = CVVISION_KEY;
    }

    AES_KEY aesKey;
    if (AES_set_encrypt_key((const unsigned char*)keyStr.c_str(), 128, &aesKey) < 0) {
        std::cout << "Error setting AES encryption key." << std::endl;
        return "";
    }

    unsigned char ivData[AES_BLOCK_SIZE] = {0};
    if (RAND_bytes(ivData, AES_BLOCK_SIZE) < 0) {
        std::cout << "Error generating random IV." << std::endl;
        return "";
    }
    std::string iv = std::string((char*)ivData, AES_BLOCK_SIZE);

    int paddedLength = ((plaintext.length() + AES_BLOCK_SIZE - 1) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE;
    unsigned char* ciphertext = new unsigned char[paddedLength];
    AES_cbc_encrypt((const unsigned char*)plaintext.c_str(), ciphertext, plaintext.length(), &aesKey, ivData, AES_ENCRYPT);

    std::string encryptedText((char*)ciphertext, paddedLength);
    delete[] ciphertext;
    return iv + encryptedText;
}

std::string AESAlgorithm::cbcDecrypt(const std::string &encryptedText, const std::string &key)
{
    std::string keyStr = key;
    if (keyStr.empty()) {
        keyStr = CVVISION_KEY;
    }

    AES_KEY aesKey;
    if (AES_set_decrypt_key((const unsigned char*)keyStr.c_str(), 128, &aesKey) < 0) {
        std::cerr << "Error setting AES decryption key." << std::endl;
        return "";
    }

    std::string iv = encryptedText.substr(0, AES_BLOCK_SIZE);
    std::string ciphertext = encryptedText.substr(AES_BLOCK_SIZE);
    unsigned char ivData[AES_BLOCK_SIZE];
    memcpy(ivData, iv.c_str(), AES_BLOCK_SIZE);

    int paddedLength = ciphertext.length();
    unsigned char* plaintext = new unsigned char[paddedLength];
    AES_cbc_encrypt((const unsigned char*)ciphertext.c_str(), plaintext, paddedLength, &aesKey, ivData, AES_DECRYPT);

    std::string decryptedText((char*)plaintext, paddedLength);
    delete[] plaintext;

    // 去掉末尾\000
    size_t nullPos = decryptedText.find('\000');
    if (nullPos > 0 && nullPos != std::string::npos) {
        // 使用erase函数删除\\000及其后面的字符
        decryptedText.erase(nullPos);
    }
    return decryptedText;
}

AESAlgorithm::AESAlgorithm()
{

}

AESAlgorithm::~AESAlgorithm()
{

}
